package com.tongcao.cn.util;

import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author Booker
 * @date 2017/7/3
 */
public class ReflectionUtils {
    private static Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);

    /**
     * 由class name 获取class对象
     *
     * @param className
     * @return
     */
    public static Class<?> getClass(String className) {
        Class<?> clazz = null;

        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            if (logger.isErrorEnabled()) {
                logger.error("由实体类名:" + className + "得到其Class对象时发生异常,未找到"
                        + className + "对应的Class对象!", e);
            }
        }
        return clazz;
    }

    /**
     * class对象初始化
     *
     * @param clazzImpl
     * @return
     */
    public static <T> T clazzInitialize(Class<T> clazzImpl) {
        T t = null;

        try {
            t = (T) clazzImpl.newInstance();
        } catch (InstantiationException e) {
            if (logger.isErrorEnabled()) {
                logger.error("将java.lang.Class对象初始化时出错!", e);
            }
        } catch (IllegalAccessException e) {
            if (logger.isErrorEnabled()) {
                logger.error("非法访问java.lang.Class对象，导致该对象初始化出错!", e);
            }
        }
        return t;
    }

    /**
     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
     * <p/>
     * 如向上转型到Object仍无法找到, 返回null.
     */
    public static Field getAccessibleField(final Object obj, final String fieldName) {
        Validate.notNull(obj, "object can't be null");
        Validate.notBlank(fieldName, "fieldName can't be blank");
        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                Field field = superClass.getDeclaredField(fieldName);
                makeAccessible(field);
                return field;
            } catch (NoSuchFieldException e) {// NOSONAR
                // Field不在当前类定义,继续向上转型
            }
        }
        return null;
    }

    /**
     * 改变private/protected的成员变量为public，尽量不调用实际改动的语句，避免JDK的SecurityManager抱怨。
     */
    public static void makeAccessible(Field field) {
        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
                .isFinal(field.getModifiers())) && !field.isAccessible()) {
            field.setAccessible(true);
        }
    }

    /**
     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
     */
    public static Object getFieldValue(final Object obj, final String fieldName) {
        Field field = getAccessibleField(obj, fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        }

        Object result = null;
        try {
            result = field.get(obj);
        } catch (IllegalAccessException e) {
            if (logger.isErrorEnabled()) {
                logger.error("不可能抛出的异常{0}", e.getMessage());
            }
        }
        return result;
    }

    public static <A extends Annotation> A getAnnotationOnParameter(
            Method method, int parameterSeq, Class<A> annotationClazz) {
        if (annotationClazz == null) {
            throw new NullPointerException("passed annotationClazz is null");
        }

        A a = null;
        Object[][] parameterAnnotations = null;

        parameterAnnotations = method.getParameterAnnotations();

        if (parameterAnnotations != null) {
            for (Object object : parameterAnnotations[parameterSeq]) {
                if (((Annotation) object).annotationType() == annotationClazz) {
                    a = (A) object;
                    break;
                }
            }
        }
        return a;
    }
}
